package com.yvan.js;

import com.yvan.platform.ReflectUtil;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
import lombok.val;

import java.util.ArrayList;
import java.util.Map;

public class JQuery {

    public static final JQuery $ = new JQuery();

    public Source source(ScriptObjectMirror factory) {
        Object scriptFunction = ReflectUtil.getValue(factory, "sobj");
        if (scriptFunction instanceof ScriptFunction) {
            Object reCompilableScriptFunctionData = ReflectUtil.getValue(scriptFunction, "data");
            return (Source) ReflectUtil.getValue(reCompilableScriptFunctionData, "source");
        }
        return null;
    }

    public boolean isArray(Object obj) {
        if (obj == null) return false;
        if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror) obj).isArray();
        }
        return false;
    }

    public boolean isFunction(Object obj) {
        if (obj == null) return false;
        if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror) obj).isFunction();
        }
        return false;
    }

    public boolean isEmpty(Object obj) {
        if (obj == null) return true;
        if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror) obj).isEmpty();
        }
        return false;
    }

    public void ajax(Map<String, Object> opts) {
        System.out.println(opts);
    }

    public boolean isPlainObject(Object obj) {
        return "object".equals($.type(obj));
    }

    public String type(Object obj) {
        if (obj == null) return "null";
        if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror) obj).getClassName().toLowerCase();

        } else if (obj instanceof Integer) {
            return "number";

        } else if (obj instanceof Boolean) {
            return "boolean";

        } else if (obj instanceof jdk.nashorn.internal.runtime.Undefined) {
            return "undefined";

        } else if (obj instanceof String) {
            return "string";

        }
        return "object";
    }

    public Object extend(Object... objects) {
        if (objects.length <= 0) {
            return new Object();
        }
        boolean deep = false;
        if (objects[0] instanceof Boolean) {
            deep = (Boolean) objects[0];
        }
        ScriptObjectMirror target = null;
        for (Object o : objects) {
            if (!(o instanceof ScriptObjectMirror)) continue;
            val options = (ScriptObjectMirror) o;
            if (target == null) {
                target = options;
                continue;
            }

            for (String name : options.getOwnKeys(false)) {
                val src = target.getMember(name);
                val copy = options.getMember(name);
                if (target == copy) {
                    continue;
                }

                boolean copyIsArray = $.isArray(copy);
                if (deep && copy != null && (copyIsArray || $.isPlainObject(copy))) {

                    Object clone;
                    if (copyIsArray) {
                        clone = (src != null && $.isArray(src)) ? src : new ArrayList();

                    } else {
                        clone = (src != null && $.isPlainObject(src)) ? src : new Object();

                    }
                    target.setMember(name, $.extend(deep, clone, copy));

                } else {
                    target.setMember(name, copy);
                }
            }
        }
        return target;
    }
}
